Semaphore
Semaphore叫做信号量,是一种共享锁,当其permit大于0时,线程可以获取锁,当permits小于0时,线程只能等待获取锁,等其他线程释放。
Semophore也有公平锁和非公平锁两种状态。
1 | //公平共享锁尝试获取acquires个信号量 |
CountDownLatch
CountDownLatch用于协调多个线程的同步,能让一个线程在等待其他线程执行完任务后,再继续执行。内部是通过一个计数器去完成实现。
CountDownLatch是通过一个计数器来实现的,计数器的初始值为线程的数量。每当一个线程完成了自己的任务后,可以调用countDown(),计数器的值就会减1。当计数器值到达0时,它表示所有的线程已经完成了任务,然后在闭锁上等待的线程(使用await()阻塞)就可以恢复执行任务。
使用场景
一个线程执行需要等待其他线程执行完毕,才能继续执行
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23public static void main(String[] args) {
CountDownLatch latch = new CountDownLatch(10);
for (int i = 0; i < 10; i++) {
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + "---start");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "---finish");
//计数器减一
latch.countDown();
}).start();
}
try {
//将主线程阻塞在latch,直到latch的计数器等于0
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("执行完毕-----");
}
常用方法
CountDownLatch通过state来表示计数器。
- await() 将当前线程阻塞在CountDownLatch上,直到计数器的数量减少至0.
- await(long timeout, TimeUnit unit),与await()不同的是,设置了超时等待,等到了时间,不管计数器是不是0,都会继续执行。
- countDown(),计数器数量减一。当计数器数量减为0时,将await()的线程唤醒。
CyclicBarrier
用来控制多个线程互相等待,只有当多个线程都到达时,这些线程才会继续执行。
和 CountdownLatch 相似,都是通过维护计数器来实现的。线程执行 await() 方法之后计数器会减 1,并进行等待,直到计数器为 0,所有调用 await() 方法而在等待的线程才能继续执行。
CyclicBarrier 和 CountdownLatch 的一个区别是,CyclicBarrier 的计数器通过调用 reset() 方法可以循环使用,所以它才叫做循环屏障。
CyclicBarrier 有两个构造函数,其中 parties 指示计数器的初始值,barrierAction 在所有线程都到达屏障的时候会执行一次。
